package com.ezcoding.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ezcoding.dao.*;
import com.ezcoding.engine.DindanCalculatorFactory;
import com.ezcoding.engine.DingdanCalculator;
import com.ezcoding.exception.STSException;
import com.ezcoding.model.*;
import com.ezcoding.utils.DateUtil;
import com.ezcoding.utils.StatusUtil;
import com.ezcoding.utils.Tools;

import java.util.*;

public class DingdanService {

    private static DingdanService instance = new DingdanService();

    public static DingdanService getInstance() {
        return instance;
    }

    /**
     * 检查订单详细是否存在重复商品记录
     *
     * @param details 订单详情
     * @return true:存在重复记录 false:不存在重复记录
     */
    private boolean checkRepeatDingdanDetails(List<DingdanDetail> details) {
        Set<String> dingdanDetailProductIds = new HashSet<>();

        for (DingdanDetail detail : details) {
            dingdanDetailProductIds.add(detail.getProductId());
        }

        return dingdanDetailProductIds.size() != details.size();
    }

    public Map<String, Object> saveDingdan(String dingdanStr, String dingdanDetailStr) {
        if (Tools.checkParaIsInValidate(dingdanStr, dingdanDetailStr)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        Dingdan dingdan = JSONObject.parseObject(dingdanStr, Dingdan.class);

        JSONArray array = JSONArray.parseArray(dingdanDetailStr);
        List<DingdanDetail> details = new ArrayList<>();

        for (int i = 0; i < array.size(); i++) {
            JSONObject obj = array.getJSONObject(i);
            DingdanDetail detail = new DingdanDetail(obj);
            details.add(detail);
        }

        if (checkRepeatDingdanDetails(details)) {
            return StatusUtil.getFailedStatusWithMessage("订单中存在重复商品请核验后提交！");
        }

        return saveDingdan(dingdan, details, null, "保存单据成功！", false);
    }

    private Map<String, Object> saveDingdan(
            Dingdan dingdan,
            List<DingdanDetail> details,
            List<Product> products,
            String successMessage,
            boolean isBuildMessage) {
        boolean add;
        String dingdanId;
        if (dingdan.getDingdanId().equals("")) {
            add = true;
            dingdanId = "" + System.currentTimeMillis();
            dingdan.setDingdanId(dingdanId);
        } else {
            dingdanId = dingdan.getDingdanId();
            Dingdan tempDingdan = DingdanDao.dao.getDingdan(dingdan.getSourceUsername(), dingdanId);
            if (tempDingdan == null) {
                return StatusUtil.getFailedStatusWithMessage("原单据不存在！");
            }
            dingdan.setId(tempDingdan.getId());
            add = false;
        }

        if (dingdan.getDate().equals("")) {
            dingdan.setDate(DateUtil.getCurrentDate());
        }

        if (add) {
            if (!dingdan.save()) {
                return StatusUtil.getFailedStatusWithMessage("保存单据失败！");
            }
        } else {
            if (!dingdan.update()) {
                return StatusUtil.getFailedStatusWithMessage("保存单据失败！");
            }
        }

        if (!add) {
            //删除原先订单详细信息
            if (DingdanDao.dao.deleteDingdanDetails(dingdan.getSourceUsername(), dingdanId) == 0) {
                return StatusUtil.getFailedStatusWithMessage("删除原订单详细信息失败！");
            }
        }

        for (DingdanDetail detail : details) {
            detail.setDingdanId(dingdanId);
            if (!detail.save()) {
                return StatusUtil.getFailedStatusWithMessage("保存单据详细信息失败！");
            }
        }

        if (products != null) {
            for (Product product : products) {
                if (!product.update()) {
                    return StatusUtil.getFailedStatusWithMessage("商品信息更新失败！");
                }
            }
        }

        if (isBuildMessage) {
            //生成消息
            Message message = MessageDao.dao.getMessage(dingdan.getSourceUsername(), dingdanId);
            if (message == null) {
                message = new Message();
                message.setSourceUsername(dingdan.getSourceUsername());
                message.setTargetUsername(dingdan.getTargetUsername());
                message.setDingdanId(dingdanId);
                if (dingdan.getType() == Dingdan.DINGDAN_TYPE_SALE_OUT || dingdan.getType() == Dingdan.DINGDAN_TYPE_SALE_BACK) {
                    message.setRelationType(UserRelation.RELATION_TYPE_CLIENT);
                } else {
                    message.setRelationType(UserRelation.RELATION_TYPE_GIVER);
                }
                message.setType(dingdan.getType());
                message.setTicketIn(dingdan.getTicketIn());
                message.setTicketOut(dingdan.getTicketOut());
                message.setMoneyIn(dingdan.getMoneyIn());
                message.setMoneyOut(dingdan.getMoneyOut());
                message.setDate(DateUtil.getCurrentDate());
                message.setOpNickName(dingdan.getOpNickName());
                message.setRemark(dingdan.getRemark());

                if (!message.save()) {
                    return StatusUtil.getFailedStatusWithMessage("消息生成失败！");
                }
            }
        }

        return StatusUtil.getSuccessStatusWithMessage(successMessage);
    }

    public Map<String, Object> deleteDingdan(String username, String dingdanId) {
        if (Tools.checkParaIsInValidate(username, dingdanId)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        Dingdan dingdan = DingdanDao.dao.getDingdan(username, dingdanId);

        if (dingdan == null) {
            return StatusUtil.getFailedStatusWithMessage("删除单据不存在！");
        }

        if (DingdanDao.dao.deleteDingdanDetails(username, dingdanId) == 0) {
            return StatusUtil.getFailedStatusWithMessage("删除单据详细信息失败！");
        }

        return StatusUtil.getStatus(dingdan.delete(), "删除单据成功！", "删除单据失败！");
    }

    public Map<String, Object> getDingdans(String username, int type, int state) {
        if (Tools.checkParaIsInValidate(username)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        List<Dingdan> dingdans = DingdanDao.dao.getDingdansByUsername(username, type, state);

        if (dingdans.size() == 0) {
            return StatusUtil.getFailedStatusWithMessage("无" + Dingdan.getStateStr(state) + "的" + Dingdan.getTypeStr(type) + "！");
        }

        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("dingdans", dingdans);
        res.put("data", data);

        return StatusUtil.getSuccessStatusWithMessage(res, "获取单据成功！");
    }

    public Map<String, Object> getDingdanDetails(String username, String dingdanId) {
        if (Tools.checkParaIsInValidate(username, dingdanId)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        Dingdan dingdan = DingdanDao.dao.getDingdan(username, dingdanId);
        if (dingdan == null) {
            return StatusUtil.getFailedStatusWithMessage("订单不存在！");
        }

        List<DingdanDetail> details = DingdanDao.dao.getDingdanDetails(username, dingdanId);
        if (details.size() == 0) {
            return StatusUtil.getFailedStatusWithMessage("单据详细信息不存在！");
        }

        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("dingdan", dingdan);
        data.put("details", details);
        res.put("data", data);

        System.out.println(details.size());

        return StatusUtil.getSuccessStatusWithMessage(res, "获取成功！");
    }

    public Map<String, Object> calculateDingdan(String dingdanStr, String detailsStr) {
        if (Tools.checkParaIsInValidate(dingdanStr, detailsStr)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        Dingdan dingdan = JSON.parseObject(dingdanStr, Dingdan.class);
        List<DingdanDetail> details = JSON.parseArray(detailsStr, DingdanDetail.class);

        DingdanCalculator calculator = DindanCalculatorFactory.create(dingdan, details);

        UserRelation relation = calculator.getUserRelation();
        Company company = calculator.getCompany();

        Map<String, Object> res = calculator.checkDingdanDetails();
        if (!StatusUtil.getStatusValue(res)) {
            return res;
        }

        calculator.calDingdanInfo();
        res = calculator.updateUserRelation();
        if (!StatusUtil.getStatusValue(res)) {
            return res;
        }

        if (company == null) {
            return StatusUtil.getFailedStatusWithMessage("企业不存在！");
        }

        calculator.updateCompanyInfo();
        if (!company.update()) {
            return StatusUtil.getFailedStatusWithMessage("企业信息更新失败！");
        }

        res = calculator.updateRelatedDingdanInfo();
        if (!StatusUtil.getStatusValue(res)) {
            return res;
        }

        dingdan.updateState();
        updateHistoryProduct(relation, details, dingdan.getType());

        List<Product> products = calculator.getProducts();

        String message = dingdan.getType() == Dingdan.DINGDAN_TYPE_PURCHASE_DINGDAN ? "采购订单发送成功！" : "单据结算成功！";

        return saveDingdan(dingdan, details, products, message, dingdan.isBuildMessage());
    }

    /**
     * 更新商品历史价格
     *
     * @param relation 采购双方用户关系
     * @param details  更新商品价格记录
     * @param type     订单类型
     */
    private void updateHistoryProduct(UserRelation relation, List<DingdanDetail> details, int type) {
        int historyType;
        if (type == Dingdan.DINGDAN_TYPE_SALE_OUT || type == Dingdan.DINGDAN_TYPE_SALE_BACK) {
            //类型为销售
            historyType = 0;
        } else {
            historyType = 1;
        }

        for (DingdanDetail detail : details) {
            HistoryProduct historyProduct = ProductDao.dao.getHistoryProductBySourceProductId(
                    relation.getSourceCompanyId(),
                    relation.getTargetCompanyId(),
                    detail.getProductId(),
                    historyType);

            boolean isSave = false;
            if (historyProduct == null) {
                historyProduct = new HistoryProduct();
                isSave = true;
            }

            historyProduct.setSourceCompanyId(relation.getSourceCompanyId());
            historyProduct.setTargetCompanyId(relation.getTargetCompanyId());
            historyProduct.setSourceProductId(detail.getProductId());
            historyProduct.setType(historyType);
            historyProduct.setHistoryPrice(detail.getPrice());

            if (isSave) {
                historyProduct.save();
            } else {
                historyProduct.update();
            }
        }
    }

    public Map<String, Object> queryDingdan(
            String typeStr,
            String sourceUsername,
            String targetUsername,
            String startTime,
            String endTime) {
        if (Tools.checkParaIsInValidate(typeStr, sourceUsername, startTime, endTime)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        if (Tools.checkParaIsNullPoint(targetUsername)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        int type = Tools.parseNatureInteger(typeStr);
        if (type != 0 && type != 1) {
            return StatusUtil.getFailedStatusWithMessage("类型参数错误！");
        }

        List<Dingdan> dingdans = DingdanDao.dao.getDingdans(sourceUsername, targetUsername, startTime, endTime, type);
        Collections.reverse(dingdans);

        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("dingdans", dingdans);
        res.put("data", data);

        return StatusUtil.getSuccessStatusWithMessage(res, "查询成功！");
    }

    public Map<String, Object> queryDingdanByDetail(
            String typeStr,
            String sourceUsername,
            String targetUsername,
            String productId,
            String startDate,
            String endDate) {
        if (Tools.checkParaIsInValidate(typeStr, sourceUsername, startDate, endDate)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        if (Tools.checkParaIsNullPoint(targetUsername, productId)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        int type = Tools.parseNatureInteger(typeStr);

        List<DingdanDetail> details = DingdanDao.dao.getDingdanDetails(
                sourceUsername,
                targetUsername,
                productId,
                startDate,
                endDate,
                type);


        List<Dingdan> dingdans = getDingdansByDetails(sourceUsername, details);
        if (dingdans == null) {
            return StatusUtil.getFailedStatusWithMessage("服务器错误！");
        }

        Collections.reverse(dingdans);
        Collections.reverse(details);

        return getDingdanAndDingdanDetail(dingdans, details);
    }

    public Map<String, Object> getDingdanDetails(
            int type,
            String sourceUsername,
            String targetUsername) {
        if (Tools.checkParaIsInValidate(sourceUsername, targetUsername)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        if (UserDao.dao.getUserByUsername(targetUsername) == null) {
            return StatusUtil.getFailedStatusWithMessage("选择用户不存在！");
        }

        List<DingdanDetail> details = DingdanDao.dao.getDingdanDetails(sourceUsername, targetUsername, type);

        if (details == null) {
            return StatusUtil.getFailedStatusWithMessage("类型参数错误！");
        }

        List<Dingdan> dingdans = getDingdansByDetails(sourceUsername, details);
        if (dingdans == null) {
            return StatusUtil.getFailedStatusWithMessage("服务器错误！");
        }

        return getDingdanAndDingdanDetail(dingdans, details);
    }

    private List<Dingdan> getDingdansByDetails(String sourceUsername, List<DingdanDetail> details) {
        List<Dingdan> dingdans = new ArrayList<>();
        for (DingdanDetail detail : details) {
            Dingdan dingdan = DingdanDao.dao.getDingdan(sourceUsername, detail.getDingdanId());
            if (dingdan == null) {
                return null;
            }
            dingdans.add(dingdan);
        }

        return dingdans;
    }

    private Map<String, Object> getDingdanAndDingdanDetail(
            List<Dingdan> dingdans,
            List<DingdanDetail> details) {
        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("details", details);
        data.put("dingdans", dingdans);
        res.put("data", data);

        return StatusUtil.getSuccessStatusWithMessage(res, "查询成功！");
    }

    public Map<String, Object> financeSubmit(
            String companyId,
            String sourceUsername,
            String targetUsername,
            String relatedMessageId,
            int relationType,
            int financeType,
            double curPreSave,
            double preSave,
            double totalFinanceMake,
            String detailsStr) {
        if (Tools.checkParaIsInValidate(companyId, sourceUsername, targetUsername, detailsStr)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        UserRelation relation = UserRelationDao.dao.getUserRelation(sourceUsername, targetUsername, relationType);
        if (relation == null) {
            return StatusUtil.getFailedStatusWithMessage("用户关系不存在！");
        }

        try {
            relation.updatePreSaveFinance(financeType, curPreSave, preSave, totalFinanceMake);
        } catch (STSException e) {
            return StatusUtil.getFailedStatusWithMessage(e.getMessage());
        }

        User user = UserDao.dao.getUserByUsername(sourceUsername);
        if (user == null) {
            return StatusUtil.getFailedStatusWithMessage("用户不存在！");
        }

        Company company = CompanyDao.dao.getCompanyByCompanyId(companyId);
        if (company == null) {
            return StatusUtil.getFailedStatusWithMessage("企业不存在！");
        }

        if (!relation.update()) {
            return StatusUtil.getFailedStatusWithMessage("预存信息更新失败！");
        }

        JSONArray array = JSONArray.parseArray(detailsStr);

        double totalTicketIn = 0;
        double totalTicketOut = 0;
        double totalMonetIn = 0;
        double totalMoneyOut = 0;
        for (int i = 0; i < array.size(); i++) {
            JSONObject obj = array.getJSONObject(i);
            String dingdanId = obj.getString("dingdan_id");
            int detailId = obj.getIntValue("id");
            Dingdan dingdan = DingdanDao.dao.getDingdan(sourceUsername, dingdanId);
            DingdanDetail detail = DingdanDetail.dao.findById(detailId);
            if (dingdan == null || detail == null) {
                return StatusUtil.getFailedStatusWithMessage("订单对应信息不存在！");
            }
            double financeMake = obj.getDouble("finance_make");
            switch (financeType) {
                case Dingdan.DINGDAN_FIN_TYPE_TICKET_IN:
                    dingdan.setTicketIn(dingdan.getTicketIn() - financeMake);
                    detail.setTicketIn(detail.getTicketIn() - financeMake);
                    totalTicketIn += financeMake;
                    break;
                case Dingdan.DINGDAN_FIN_TYPE_TICKET_OUT:
                    dingdan.setTicketOut(dingdan.getTicketOut() - financeMake);
                    detail.setTicketOut(detail.getTicketOut() - financeMake);
                    totalTicketOut += financeMake;
                    break;
                case Dingdan.DINGDAN_FIN_TYPE_MONEY_IN:
                    dingdan.setMoneyIn(dingdan.getMoneyIn() - financeMake);
                    detail.setMoneyIn(detail.getMoneyIn() - financeMake);
                    totalMonetIn += financeMake;
                    break;
                case Dingdan.DINGDAN_FIN_TYPE_MONEY_OUT:
                    dingdan.setMoneyOut(dingdan.getMoneyOut() - financeMake);
                    detail.setMoneyOut(detail.getMoneyOut() - financeMake);
                    totalMoneyOut += financeMake;
                    break;
            }
            if (!dingdan.update() || !detail.update()) {
                return StatusUtil.getFailedStatusWithMessage("更新订单记录失败！");
            }
        }

        company.updateFinance(financeType, totalFinanceMake);
        if (!company.update()) {
            return StatusUtil.getFailedStatusWithMessage("企业信息更新失败！");
        }

        //删除关联消息
        Message relatedMessage = MessageDao.dao.getMessageById(targetUsername, relatedMessageId);
        if (relatedMessage != null) {
            if (!relatedMessage.delete()) {
                return StatusUtil.getFailedStatusWithMessage("关联消息删除失败！");
            }
        }

        String successMessage = "";
        boolean isBuildMessage = false;//收款、收票不建立消息
        switch (financeType) {
            case Dingdan.DINGDAN_FIN_TYPE_TICKET_IN:
                successMessage = "收票成功！";
                isBuildMessage = false;
                break;
            case Dingdan.DINGDAN_FIN_TYPE_TICKET_OUT:
                successMessage = "开票成功！";
                isBuildMessage = true;
                break;
            case Dingdan.DINGDAN_FIN_TYPE_MONEY_IN:
                successMessage = "收款成功！";
                isBuildMessage = false;
                break;
            case Dingdan.DINGDAN_FIN_TYPE_MONEY_OUT:
                successMessage = "付款成功！";
                isBuildMessage = true;
                break;
        }

        if (isBuildMessage) {
            //建立消息 消息值记为负数
            Message message = new Message(
                    sourceUsername,
                    targetUsername,
                    relationType,
                    totalTicketIn * -1,
                    totalTicketOut * -1,
                    totalMonetIn * -1,
                    totalMoneyOut * -1,
                    financeType,
                    user.getNickName(),
                    "");

            message.setDingdanId(relatedMessageId);

            if (!message.save()) {
                return StatusUtil.getFailedStatusWithMessage("消息建立失败！");
            }
        }

        return StatusUtil.getSuccessStatusWithMessage(successMessage);
    }

    public Map<String, Object> getHistoryProducts(
            String sourceCompanyId,
            String targetCompanyId,
            String sourceProductId,
            int type) {
        if (Tools.checkParaIsNullPoint(sourceCompanyId, targetCompanyId, sourceProductId)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        List<HistoryProduct> historyProducts = ProductDao.dao.getHistoryProducts(
                sourceCompanyId,
                targetCompanyId,
                sourceProductId,
                type);

        List<Company> companyList = new ArrayList<>();

        for (HistoryProduct historyProduct : historyProducts) {
            Company company = CompanyDao.dao.getCompanyByCompanyId(historyProduct.getTargetCompanyId());
            if (company == null) {
                return StatusUtil.getFailedStatusWithMessage("对方企业不存在[" + historyProduct.getTargetCompanyId() + "]");
            }
            companyList.add(company);
        }

        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("historyProducts", historyProducts);
        data.put("companyList", companyList);
        res.put("data", data);

        return StatusUtil.getSuccessStatusWithMessage(res, "历史价格获取成功！");
    }

    public Map<String, Object> getImportDingdans(String username, int state) {
        if (Tools.checkParaIsInValidate(username)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        List<Dingdan> dingdans = DingdanDao.dao.getImportDingdans(username, state);
        Collections.reverse(dingdans);

        if (dingdans.size() == 0) {
            return StatusUtil.getFailedStatusWithMessage("无" + Dingdan.getStateStr(state) + "的订单！");
        }

        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("dingdans", dingdans);
        res.put("data", data);

        return StatusUtil.getSuccessStatusWithMessage(res, "获取导入单据成功！");
    }

    public Map<String, Object> getImportDingdanDetails(
            String sourceUsername,
            String targetUsername,
            String sourceCompanyId,
            String targetCompanyId,
            String dingdanId,
            int type) {
        if (Tools.checkParaIsInValidate(sourceUsername, targetUsername, sourceCompanyId, targetCompanyId, dingdanId)) {
            return StatusUtil.getFailedStatusWithInvalidParaMessage();
        }

        //获取对方订单详情
        List<DingdanDetail> targetDetails = DingdanDao.dao.getDingdanDetails(targetUsername, dingdanId);

        if (targetDetails.size() == 0) {
            return StatusUtil.getFailedStatusWithMessage("单据详细信息不存在！");
        }

        //我方订单详情
        List<DingdanDetail> sourceDetails = new ArrayList<>();
        //我方商品详情
        List<Product> sourceProducts = new ArrayList<>();
        //对方商品详情
        List<Product> targetProducts = new ArrayList<>();
        //更新历史价格商品对应关系，将对方商品转换为我方对应数量商品
        for (DingdanDetail targetDetail : targetDetails) {
            HistoryProduct historyProduct = ProductDao.dao.getHistoryProductByTargetProductId(
                    sourceCompanyId,
                    targetCompanyId,
                    targetDetail.getProductId(),
                    type);

            Product sourceProduct;
            Product targetProduct = ProductDao.dao.getProductByCompanyIdAndProductId(
                    targetCompanyId,
                    targetDetail.getProductId());
            DingdanDetail sourceDetail = new DingdanDetail();
            if (historyProduct == null) {
                //对方商品和我方商品无对应关系，对应建立我方空商品记录
                sourceProduct = new Product();
            } else {
                //对方商品和我方商品有对应关系，根据比例关系建立我方商品记录
                sourceProduct = ProductDao.dao.getProductByCompanyIdAndProductId(
                        sourceCompanyId,
                        historyProduct.getSourceProductId());
                if (sourceProduct != null) {
                    sourceDetail.setProductId(sourceProduct.getProductId());
                    sourceDetail.setCount(historyProduct.getProductCount(targetDetail.getCount()));
                    sourceDetail.setPrice(historyProduct.getHistoryPrice());
                } else {
                    sourceProduct = new Product();
                }
            }

            sourceDetails.add(sourceDetail);
            sourceProducts.add(sourceProduct);
            targetProducts.add(targetProduct);
        }

        Map<String, Object> res = new HashMap<>();
        Map<String, Object> data = new HashMap<>();

        data.put("sourceDetails", sourceDetails);
        data.put("sourceProducts", sourceProducts);
        data.put("targetDetails", targetDetails);
        data.put("targetProducts", targetProducts);
        res.put("data", data);

        return StatusUtil.getSuccessStatusWithMessage(res, "获取成功！");
    }
}
